﻿using LightWadf.Core.Analyzer;
using LightWadf.Core.Filter;
using LightWadf.Core.Processor;
using LightWadf.Core.Route;
using LightWadf.Core.Util;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace LightWadf.Core.Handler
{
    public class DefaultHandler : ICustomHttpHandler
    {
        /// <summary>
        /// 整个项目所有的路由
        /// </summary>
        private static DefaultRoute Route = null;

        /// <summary>
        /// 过滤器集合
        /// </summary>
        private static Dictionary<Attribute, IFilter> Filters = new Dictionary<Attribute, IFilter>();

        /// <summary>
        /// 过滤器属性集合
        /// </summary>
        private static Dictionary<string, List<Attribute>> FilterAttributes = new Dictionary<string, List<Attribute>>();

        static DefaultHandler()
        {
            Route = new DefaultRoute();

            // 扫描所有的处理器，获取其路由
            foreach (Type type in Utility.Assembly.ExportedTypes)
            {
                #region 处理 处理器类型
                if(typeof(AbstractProcessor).IsAssignableFrom(type))
                {
                    // 获取处理器的过滤器
                    if (!FilterAttributes.ContainsKey(type.FullName))
                    {
                        var attributes = type.GetTypeInfo().GetCustomAttributes(typeof(IFilter)).ToList();
                        if (attributes != null && attributes.Count != 0)
                        {
                            FilterAttributes[type.FullName] = attributes;
                        }
                    }
                    // 遍历处理器方法，获取方法的过滤器
                    foreach (MethodInfo method in type.GetMethods())
                    {
                        string key = type.FullName + '.' + method.Name;
                        if (!FilterAttributes.ContainsKey(key))
                        {
                            var attributes = method.GetCustomAttributes(typeof(IFilter)).ToList();
                            if (attributes != null && attributes.Count != 0)
                            {
                                FilterAttributes[key] = attributes;
                            }
                        }
                    }

                    // 遍历 filterAttributes，创建过滤器实例
                    foreach (var item in FilterAttributes)
                    {
                        foreach (var attribute in item.Value)
                        {
                            if (!Filters.ContainsKey(attribute))
                                Filters.Add(attribute, Activator.CreateInstance(attribute.GetType()) as IFilter);
                        }
                    }

                    try
                    {
                        AbstractProcessor processor = Activator.CreateInstance(type) as AbstractProcessor;  
                        if (processor != null)
                        {
                            processor.InitRouteRule();
                            Route.MergeRoute(processor.Route);
                        }
                    }
                    catch (Exception e)
                    {
                    }
                }
                #endregion
            }
        }

        public async Task ProcessRequest(HttpContext context)
        {
            var matchResult = Route.Match(context.Request.Path, context.Request.Method);
            if (matchResult == null)
            {
                context.Response.StatusCode = 404;
            }
            else
            {
                RouteTrie routeTrie = matchResult.Item1;
                if (routeTrie == null || string.IsNullOrEmpty(routeTrie.ProcessorName) || string.IsNullOrEmpty(routeTrie.MethodName))
                {
                    context.Response.StatusCode = 404;
                }
                else
                {
                    try
                    {
                        object result = null;
                        // 处理器的前置处理(Before Filter)
                        List<Attribute> processorAttributes = null;
                        if (FilterAttributes.ContainsKey(routeTrie.ProcessorName))
                        {
                            processorAttributes = FilterAttributes[routeTrie.ProcessorName];
                        }
                        if (processorAttributes != null)
                        {
                            processorAttributes.Reverse();
                            result = this.DoBeforeFilter(processorAttributes, context);
                        }

                        // 逻辑处理方法的前置处理
                        string methodName = routeTrie.ProcessorName + '.' + routeTrie.MethodName;
                        List<Attribute> methodAttributes = null;
                        if (FilterAttributes.ContainsKey(methodName))
                        {
                            methodAttributes = FilterAttributes[methodName];
                        }
                        if (result == null && methodAttributes != null)
                        {
                            methodAttributes.Reverse();
                            result = this.DoBeforeFilter(methodAttributes, context);
                        }

                        // 处理器调用逻辑处理方法
                        if (result == null)
                        {
                            //var asyncResult = matchResult.Item1.Delegate.BeginInvoke(context, matchResult.Item2, null, null);
                            //asyncResult.AsyncWaitHandle.WaitOne();
                            //result = matchResult.Item1.Delegate.EndInvoke(asyncResult);
                            //if (result is Task)
                            //{
                            //    var property = result.GetType().GetProperty("Result");
                            //    if (property != null)
                            //        result = property.GetValue(result);
                            //    else result = null;
                            //}
                            var processResult = matchResult.Item1.Delegate.Invoke(context, matchResult.Item2);
                            if (processResult is Task)
                            {
                                Task task = processResult as Task;
                                await task.ContinueWith(t =>
                                {
                                    var property = processResult.GetType().GetProperty("Result");
                                    if (property != null)
                                        result = property.GetValue(processResult);
                                    else result = null;
                                });
                            }
                            else
                            {
                                result = processResult;
                            }
                        }

                        // 逻辑处理方法的后置处理
                        if (methodAttributes != null)
                        {
                            methodAttributes.Reverse();
                            this.DoAfterFilter(methodAttributes, context, ref result);
                        }

                        // 处理器的后置处理(After Filter)
                        if (processorAttributes != null)
                        {
                            processorAttributes.Reverse();
                            this.DoAfterFilter(processorAttributes, context, ref result);
                        }

                        foreach (IResultAnalyzer analyzer in Utility.GlobalConfiguration.ResultAnalyzers)
                        {
                            if(analyzer != null)
                                await analyzer.Parse(result, context);
                        }
                    }
                    catch (Exception e)
                    {
                        await context.Response.WriteAsync(e.Message);
                    }
                }
            }
        }

        private object DoBeforeFilter(IEnumerable<Attribute> attributes, HttpContext context)
        {
            if (attributes != null)
            {
                IFilter filter = null;
                foreach (var attribute in attributes)
                {
                    filter = Filters[attribute];
                    object result = filter.BeforeProcess(context);
                    if (result != null) return result;
                }
            }
            return null;
        }

        private void DoAfterFilter(IEnumerable<Attribute> attributes, HttpContext context, ref object result)
        {
            if (attributes != null)
            {
                IFilter filter = null;
                foreach (var attribute in attributes)
                {
                    filter = Filters[attribute];
                    filter.AfterProcess(context, ref result);
                }
            }
        }
    }
}